import { Singleton } from "../utils/Singleton";

const { ccclass } = cc._decorator;

type CallbackData = {
  callback: Function;
  thisObj: any;
};

@ccclass
export default class EventManager extends Singleton<EventManager> {
  private eventsMap = new Map<string, Array<CallbackData>>();

  private constructor() {
    super();
  }
  // 注册监听器（订阅事件）
  on(type: string, callback: Function, thisObj: any): void {
    if (!callback) return;

    let callbacks = this.eventsMap.get(type);
    if (!callbacks) {
      callbacks = [];
      this.eventsMap.set(type, callbacks);
    }

    const index = this.findCallbackIndex(callbacks, callback, thisObj);
    if (index === -1) {
      callbacks.push({ callback, thisObj });
    }
  }

  // 注册仅触发一次的监听器
  once(type: string, callback: Function, thisObj: any): void {
    const wrappedCallback = (...args: any[]) => {
      callback.apply(thisObj, args);
      this.off(type, wrappedCallback, thisObj);
    };
    this.on(type, wrappedCallback, thisObj);
  }

  // 事件注销
  off(type: string, callback: Function, thisObj: any): void {
    const callbacks = this.eventsMap.get(type);
    if (!callbacks) return;

    const index = this.findCallbackIndex(callbacks, callback, thisObj);
    if (index !== -1) {
      callbacks.splice(index, 1);
    }

    if (callbacks.length === 0) {
      this.eventsMap.delete(type);
    }
  }

  // 注销指定节点的事件
  offByTarget(target: any): void {
    Array.from(this.eventsMap.entries()).forEach(([type, callbacks]) => {
      for (let i = callbacks.length - 1; i >= 0; i--) {
        if (callbacks[i].thisObj === target) {
          callbacks.splice(i, 1);
        }
      }
      if (callbacks.length === 0) {
        this.eventsMap.delete(type);
      }
    });
  }

  // 触发事件（发布事件）
  execute(type: string, ...params: any[]): void {
    const callbacks = this.eventsMap.get(type);
    if (!callbacks || callbacks.length === 0) return;

    for (const { callback, thisObj } of [...callbacks]) {
      // 使用浅拷贝避免在遍历时修改原数组
      callback.apply(thisObj, params);
    }
  }

  // 清除所有事件监听器
  clearAll(): void {
    this.eventsMap.clear();
  }

  private findCallbackIndex(
    list: Array<CallbackData>,
    callback: Function,
    thisObj: any
  ): number {
    for (let i = 0; i < list.length; i++) {
      const data = list[i];
      if (data.callback === callback && data.thisObj === thisObj) {
        return i;
      }
    }
    return -1;
  }
}
